package com.ygqh.baby.kids.service.impl;

import com.mumu.commons.utils.StringUtils;
import com.ygqh.baby.ao.OffShop;
import com.ygqh.baby.kids.entity.bo.KidsOrder;
import com.ygqh.baby.kids.entity.bo.KidsOrderDetail;
import com.ygqh.baby.kids.service.KidsOrderService;
import com.ygqh.baby.po.*;
import com.ygqh.baby.service.AdminSkuService;
import com.ygqh.baby.service.BiOrderDayService;
import com.ygqh.baby.service.BiSkuSaleService;
import com.ygqh.baby.service.YgSupplierService;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: sunshuo
 * @Date: 2019/3/5 13:48
 * @Version: 1.0
 */
@Service
public class KidsOrderServiceImpl implements KidsOrderService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private YgSupplierService ygSupplierService;
    @Autowired
    private BiOrderDayService biOrderDayService;
    @Autowired
    private BiSkuSaleService biSkuSaleService;
    @Autowired
    private AdminSkuService adminSkuService;

    @Override
    public void buildBiOrderDayFromKids(List<KidsOrder> orderList, Date orderDate, OffShop offShop) {
        buildBiOrderDayFromKidsByWarehouseNo(orderList, offShop);
    }

    private void buildBiOrderDayFromKidsByOrder(List<KidsOrder> orderList, Date orderDate, OffShop offShop) {
        BigDecimal totalOrderPrice = BigDecimal.ZERO;
        List<Long> userIdList = new ArrayList<>();
        List<String> skuCodeList = new ArrayList<>();
        List<BiSkuSale> skuSaleList = new ArrayList<>();
        for (KidsOrder order : orderList) {
            totalOrderPrice = totalOrderPrice.add(order.getTotalPrice());
            if (!userIdList.contains(order.getUserId())) {
                userIdList.add(order.getUserId());
            }
            order.getOrderDetailList().forEach(detail ->
                    skuSaleList.add(buildBiSkuSaleFromKids(detail, orderDate, offShop, skuCodeList)));
        }
        BiOrderDay orderDay = new BiOrderDay();
        orderDay.setOrderDate(orderDate);
        orderDay.setShopType(offShop.getShopNo());
        orderDay.setShopName(offShop.getShopName());
        orderDay.setTotalOrderCount((long) orderList.size());
        orderDay.setTotalOrderPrice(totalOrderPrice);
        orderDay.setTotalUserCount((long) userIdList.size());
        orderDay.setPayOrderCount(orderDay.getTotalOrderCount());
        orderDay.setPayOrderPrice(orderDay.getTotalOrderPrice());
        orderDay.setPayUserCount(orderDay.getTotalUserCount());
        processBiOrderAndSku(orderDay, skuSaleList, skuCodeList);

        BiOrderDay orderDayFromDB = biOrderDayService.findByShop(offShop.getShopNo(), orderDate);
        int row;
        if (orderDayFromDB != null) {
            row = biOrderDayService.additionBatch(Collections.singletonList(orderDay));
        } else {
            row = biOrderDayService.save(orderDay);
        }
        if (row > 0 && CollectionUtils.isNotEmpty(skuSaleList)) {
            saveBiSkuSale(skuSaleList, orderDate, offShop.getShopName());
        }
    }

    private void buildBiSkuSale(List<KidsOrderDetail> orderDetailList, Date orderDate, OffShop offShop) {
        List<BiSkuSale> skuSaleList = new ArrayList<>();
        orderDetailList.forEach(detail -> {
            BiSkuSale biSkuSale = doBuildSkuSale(detail, offShop, orderDate, detail.getAdminProductName());
            skuSaleList.add(biSkuSale);
        });
        saveBiSkuSale(skuSaleList, orderDate, offShop.getShopName());
    }

    private void buildBiOrderDayFromKidsByWarehouseNo(List<KidsOrder> orderList, OffShop offShop) {
        Map<Date, List<KidsOrder>> dateListMap = orderList.stream().collect(Collectors.groupingBy(KidsOrder::getOrderDate));
        for (Map.Entry<Date, List<KidsOrder>> listEntry : dateListMap.entrySet()) {
            Date key = listEntry.getKey();
            List<KidsOrderDetail> orderDetailList = initKidsOrderDetailList(orderList);

            Map<String, List<BiOrderDay>> map = buildBiOrderDayMap(orderDetailList, key, offShop);
            List<BiOrderDay> newList = map.get("newList");
            List<BiOrderDay> oldList = map.get("oldList");
            biOrderDayService.additionBatch(oldList);
            biOrderDayService.addBiOrderDayBatch(newList);

            buildBiSkuSale(orderDetailList, key, offShop);

        }

    }

    private List<KidsOrderDetail> initKidsOrderDetailList(List<KidsOrder> orderList) {
        List<KidsOrderDetail> orderDetailList = orderList.stream().flatMap(order -> order.getOrderDetailList().stream()).collect(Collectors.toList());
        List<String> skuCodeList = orderDetailList.stream().map(KidsOrderDetail::getSkuCode).distinct().collect(Collectors.toList());
        List<AdminSku> listBySkuCode = adminSkuService.findListBySkuCode(skuCodeList);
        Map<String, List<AdminSku>> listMap = listBySkuCode.stream().collect(Collectors.groupingBy(AdminSku::getSkuCode));
        orderDetailList.forEach(detail -> {
            List<AdminSku> adminSkuList = listMap.get(detail.getSkuCode());
            if (CollectionUtils.isNotEmpty(adminSkuList)) {
                AdminSku adminSku = adminSkuList.get(0);
                detail.setCostPrice(adminSku.getMaterial().getCostPrice().multiply(new BigDecimal(detail.getQuantity())));
                detail.setWarehouseNo(adminSku.getWarehouseNo());
            } else {
                detail.setCostPrice(BigDecimal.ZERO);
                detail.setWarehouseNo("009");
            }
        });
        return orderDetailList;
    }

    private Map<String, List<BiOrderDay>> buildBiOrderDayMap(List<KidsOrderDetail> orderDetailList, Date orderDate, OffShop offShop) {
        List<BiOrderDay> newList = new ArrayList<>();
        List<BiOrderDay> oldList = new ArrayList<>();

        Map<String, List<KidsOrderDetail>> warehouseMap = orderDetailList.stream().collect(Collectors.groupingBy(KidsOrderDetail::getWarehouseNo));

        BigDecimal totalOrderPrice = BigDecimal.ZERO;
        BigDecimal totalCostPrice = BigDecimal.ZERO;
        Set<Long> userSet = new HashSet<>();
        Set<String> orderSet = new HashSet<>();

        for (Map.Entry<String, List<KidsOrderDetail>> listEntry : warehouseMap.entrySet()) {
            Set<Long> subUserSet = new HashSet<>();
            Set<String> subOrderSet = new HashSet<>();

            BigDecimal subTotalPrice = BigDecimal.ZERO;
            BigDecimal subCostPrice = BigDecimal.ZERO;
            for (KidsOrderDetail detail : listEntry.getValue()) {
                subUserSet.add(detail.getUserId());
                subOrderSet.add(detail.getOrderCode());
                subTotalPrice = subTotalPrice.add(detail.getTotalPrice());
                subCostPrice = subCostPrice.add(detail.getCostPrice());
            }
            totalOrderPrice = totalOrderPrice.add(subTotalPrice);
            totalCostPrice = totalCostPrice.add(subCostPrice);
            userSet.addAll(subUserSet);
            orderSet.addAll(subOrderSet);

            BiOrderDay subOrderDay = new BiOrderDay();
            subOrderDay.setOrderDate(orderDate);
            subOrderDay.setShopType(offShop.getShopNo());
            subOrderDay.setShopName(offShop.getShopName());
            subOrderDay.setTotalOrderCount((long) subOrderSet.size());
            subOrderDay.setTotalOrderPrice(subTotalPrice);
            subOrderDay.setTotalUserCount((long) subUserSet.size());
            subOrderDay.setPayOrderCount(subOrderDay.getTotalOrderCount());
            subOrderDay.setPayOrderPrice(subOrderDay.getTotalOrderPrice());
            subOrderDay.setPayUserCount(subOrderDay.getTotalUserCount());
            subOrderDay.setTotalCostPrice(subCostPrice);
            subOrderDay.setWarehouseNo(listEntry.getKey());
            subOrderDay.setGrossMargin(grossMargin(subTotalPrice, subCostPrice));
            subOrderDay.setUpdateTime(new Date());
            subOrderDay.setCreateTime(new Date());

            addToList(subOrderDay, newList, oldList);
        }

        BiOrderDay orderDay = new BiOrderDay();
        orderDay.setOrderDate(orderDate);
        orderDay.setShopType(offShop.getShopNo());
        orderDay.setShopName(offShop.getShopName());
        orderDay.setTotalOrderCount((long) orderSet.size());
        orderDay.setTotalOrderPrice(totalOrderPrice);
        orderDay.setTotalUserCount((long) userSet.size());
        orderDay.setPayOrderCount(orderDay.getTotalOrderCount());
        orderDay.setPayOrderPrice(orderDay.getTotalOrderPrice());
        orderDay.setPayUserCount(orderDay.getTotalUserCount());
        orderDay.setTotalCostPrice(totalCostPrice);
        orderDay.setUpdateTime(new Date());
        orderDay.setCreateTime(new Date());
        orderDay.setWarehouseNo("0");
        orderDay.setGrossMargin(grossMargin(totalOrderPrice, totalCostPrice));
        addToList(orderDay, newList, oldList);

        Map<String, List<BiOrderDay>> map = new HashMap<>();
        map.put("newList", newList);
        map.put("oldList", oldList);
        return map;
    }

    private BiSkuSale doBuildSkuSale(KidsOrderDetail detail, OffShop offShop, Date orderDate, String adminProductName) {
        BiSkuSale skuSale = new BiSkuSale();
        skuSale.setBiDate(orderDate);
        skuSale.setShopNo(offShop.getShopNo());
        skuSale.setShopName(offShop.getShopName());
        skuSale.setProductName(StringUtils.isBlank(detail.getSourceProductName()) ?
                detail.getProductName() : detail.getSourceProductName());
        skuSale.setProductCode(detail.getProductCode());
        skuSale.setSkuCode(detail.getSkuCode());
        skuSale.setShortName(detail.getColor());
        skuSale.setSize(detail.getSizeName());
        skuSale.setAmount(detail.getQuantity());
        if (StringUtils.isBlank(adminProductName)) {
            adminProductName = skuSale.getProductName();
        }
        skuSale.setAdminProductName(adminProductName);
        return skuSale;
    }

    private void addToList(BiOrderDay biOrderDay, List<BiOrderDay> newList, List<BiOrderDay> oldList) {
        BiOrderDay orderDayFromDB = biOrderDayService.findByShop(biOrderDay.getShopType(), biOrderDay.getOrderDate(), biOrderDay.getWarehouseNo());
        if (orderDayFromDB == null) {
            newList.add(biOrderDay);
        } else {
            oldList.add(biOrderDay);
        }
    }

    @Override
    public List<BiSupplierOrderDay> buildBiSupplierOrderDayFromKids(List<KidsOrder> orderList, Date orderDate,
                                                                    OffShop offShop) {
        Map<String, List<KidsOrderDetail>> detailMap = new HashMap<>();
        Map<String, List<Long>> orderIdMap = new HashMap<>();
        Map<String, List<Long>> userIdMap = new HashMap<>();
        List<String> skuCodeList = new ArrayList<>();
        groupOrderBySupplier(orderList, detailMap, orderIdMap, userIdMap, skuCodeList);

        List<YgSupplier> supplierList = ygSupplierService.findListBySupplierName(new ArrayList<>(detailMap.keySet()));
        if (supplierList == null) {
            logger.warn(offShop.getShopName() + "商家名称不匹配，supplierNameList={}", detailMap.keySet());
            supplierList = new ArrayList<>(1);
        }
        Map<String, List<YgSupplier>> supplierMap =
                supplierList.stream().collect(Collectors.groupingBy(YgSupplier::getSupplierName));
        List<AdminSku> adminSkuList = adminSkuService.findListBySkuCode(skuCodeList);
        if (adminSkuList == null) {
            logger.warn(offShop.getShopName() + "SKU编码不匹配，skuCodeList={}", skuCodeList);
            adminSkuList = new ArrayList<>(1);
        }
        Map<String, List<AdminSku>> skuMap =
                adminSkuList.stream().collect(Collectors.groupingBy(AdminSku::getSkuCode));
        List<BiSupplierOrderDay> orderDayList = new ArrayList<>(detailMap.size());
        detailMap.forEach((supplierName, detailList) ->
                orderDayList.add(
                        buildBiSupplierOrderDayFromKids(supplierName, detailList, orderDate, offShop,
                                (long) orderIdMap.get(supplierName).size(), (long) userIdMap.get(supplierName).size(),
                                (supplierMap.containsKey(supplierName) ? supplierMap.get(supplierName).get(0).getId() : null),
                                skuMap)));
        return orderDayList;
    }

    @Override
    public void resetBiOrder(List<KidsOrder> orderList, OffShop offShop) {
        Map<Date, List<KidsOrder>> dateListMap = orderList.stream().collect(Collectors.groupingBy(KidsOrder::getOrderDate));
        for (Map.Entry<Date, List<KidsOrder>> listEntry : dateListMap.entrySet()) {
            Date key = listEntry.getKey();
            List<KidsOrder> subList = listEntry.getValue();
            List<KidsOrderDetail> orderDetailList = initKidsOrderDetailList(subList);

            Map<String, List<BiOrderDay>> map = buildBiOrderDayMap(orderDetailList, key, offShop);
            List<BiOrderDay> newList = map.get("newList");
            List<BiOrderDay> oldList = map.get("oldList");
            biOrderDayService.updateBatch(oldList);
            biOrderDayService.addBiOrderDayBatch(newList);


        }
    }

    /**
     * 组装按商家订单统计数据
     *
     * @param supplierName    商家名称
     * @param detailList      订单明细集
     * @param orderDate       统计日期
     * @param offShop         店铺
     * @param totalOrderCount 订单总数
     * @param totalUserCount  用户总数
     * @param supplierId      商家id
     * @param skuMap          SKU信息组
     * @return
     */
    private BiSupplierOrderDay buildBiSupplierOrderDayFromKids(String supplierName, List<KidsOrderDetail> detailList,
                                                               Date orderDate, OffShop offShop, Long totalOrderCount,
                                                               Long totalUserCount, Long supplierId,
                                                               Map<String, List<AdminSku>> skuMap) {
        BiSupplierOrderDay orderDay = new BiSupplierOrderDay();
        orderDay.setOrderDate(orderDate);
        orderDay.setTotalOrderCount(totalOrderCount);
        orderDay.setTotalUserCount(totalUserCount);
        orderDay.setPayOrderCount(orderDay.getTotalOrderCount());
        orderDay.setPayUserCount(orderDay.getTotalUserCount());
        orderDay.setPlatformNo(offShop.getPlatformNo());
        orderDay.setPlatformName(offShop.getShopName());
        orderDay.setSupplierName(supplierName);
        if (supplierId != null) {
            orderDay.setSupplierId(supplierId);
        } else {
            logger.warn(offShop.getShopName() + "商家名称不匹配，supplierName={}", supplierName);
            orderDay.setSupplierId(detailList.get(0).getSupplierId());
        }

        BigDecimal totalOrderPrice = BigDecimal.ZERO;
        BigDecimal totalSalePrice = BigDecimal.ZERO;
        BigDecimal totalCostPrice = BigDecimal.ZERO;
        for (KidsOrderDetail detail : detailList) {
            totalOrderPrice = totalOrderPrice.add(detail.getTotalPrice());
            totalSalePrice = totalSalePrice.add(
                    detail.getSalePrice().multiply(BigDecimal.valueOf(detail.getQuantity())));
            if (skuMap.containsKey(detail.getSkuCode())) {
                BigDecimal costPrice = skuMap.get(detail.getSkuCode()).get(0).getMaterial().getCostPrice();
                totalCostPrice = totalCostPrice.add(costPrice.multiply(BigDecimal.valueOf(detail.getQuantity())));
            } else {
                logger.warn(offShop.getShopName() + "SKU编码不匹配，skuCode={}", detail.getSkuCode());
            }
        }
        orderDay.setTotalOrderPrice(totalOrderPrice);
        orderDay.setPayOrderPrice(totalOrderPrice);
        orderDay.setTotalSalePrice(totalSalePrice);
        orderDay.setTotalCostPrice(totalCostPrice);
        orderDay.setGrossMargin(grossMargin(totalOrderPrice, totalCostPrice));
        return orderDay;
    }

    /**
     * 按商家分组订单集
     *
     * @param orderList   订单集
     * @param detailMap   订单明细组
     * @param orderIdMap  订单id组
     * @param userIdMap   用户id组
     * @param skuCodeList SKU编码集
     */
    private void groupOrderBySupplier(List<KidsOrder> orderList, Map<String, List<KidsOrderDetail>> detailMap,
                                      Map<String, List<Long>> orderIdMap, Map<String, List<Long>> userIdMap,
                                      List<String> skuCodeList) {
        orderList.forEach(order -> order.getOrderDetailList().forEach(detail -> {
            String supplierName = detail.getSupplierName();
            List<KidsOrderDetail> detailList = detailMap.get(supplierName);
            if (detailList == null) {
                detailList = new ArrayList<>();
            }
            detailList.add(detail);
            detailMap.put(supplierName, detailList);

            List<Long> orderIdList = orderIdMap.get(supplierName);
            if (orderIdList == null) {
                orderIdList = new ArrayList<>();
            }
            if (!orderIdList.contains(order.getId())) {
                orderIdList.add(order.getId());
            }
            orderIdMap.put(supplierName, orderIdList);

            List<Long> userIdList = userIdMap.get(supplierName);
            if (userIdList == null) {
                userIdList = new ArrayList<>();
            }
            if (!userIdList.contains(order.getUserId())) {
                userIdList.add(order.getUserId());
            }
            userIdMap.put(supplierName, userIdList);

            if (!skuCodeList.contains(detail.getSkuCode())) {
                skuCodeList.add(detail.getSkuCode());
            }
        }));
    }

    /**
     * 保存订单SKU信息到数据库
     *
     * @param biSkuSaleList
     * @param orderDate
     */
    private void saveBiSkuSale(List<BiSkuSale> biSkuSaleList, Date orderDate, String shopName) {
        List<BiSkuSale> newSkuList = new ArrayList<>();
        List<BiSkuSale> oldSkuList = new ArrayList<>();

        // 对应数据库已存在商品信息
        List<BiSkuSale> skuSaleListFromDB = biSkuSaleService.findSkuSaleList(orderDate, shopName);
        List<String> skuCodeExistsDB = null;
        if (CollectionUtils.isNotEmpty(skuSaleListFromDB)) {
            skuCodeExistsDB = skuSaleListFromDB.stream().map(BiSkuSale::getSkuCode).collect(Collectors.toList());
        }
        for (BiSkuSale biSkuSale : biSkuSaleList) {
            if (skuCodeExistsDB != null && skuCodeExistsDB.contains(biSkuSale.getSkuCode())) {
                oldSkuList.add(biSkuSale);
            } else {
                newSkuList.add(biSkuSale);
            }
        }
        biSkuSaleService.addBatch(newSkuList);
        biSkuSaleService.additionAmountBatch(oldSkuList);
    }

    private void processBiOrderAndSku(BiOrderDay orderDay, List<BiSkuSale> skuSaleList, List<String> skuCodeList) {
        List<AdminSku> adminSkuList = adminSkuService.findListBySkuCode(skuCodeList);
        if (adminSkuList == null) {
            logger.warn(orderDay.getShopName() + "SKU编码不匹配，skuCodeList={}", skuCodeList);
            adminSkuList = new ArrayList<>(1);
        }
        Map<String, List<AdminSku>> collect =
                adminSkuList.stream().collect(Collectors.groupingBy(AdminSku::getSkuCode));
        BigDecimal totalCostPrice = BigDecimal.ZERO;
        for (BiSkuSale skuSale : skuSaleList) {
            if (!collect.containsKey(skuSale.getSkuCode())) {
                logger.warn(orderDay.getShopName() + "SKU编码不匹配，skuCode={}", skuSale.getSkuCode());
                skuSale.setAdminProductName(skuSale.getProductName());
                continue;
            }
            AdminSku adminSku = collect.get(skuSale.getSkuCode()).get(0);
            skuSale.setAdminProductName(adminSku.getProductName());
            totalCostPrice = totalCostPrice.add(adminSku.getMaterial().getCostPrice());
        }
        orderDay.setTotalCostPrice(totalCostPrice);
        orderDay.setGrossMargin(grossMargin(orderDay.getPayOrderPrice(), totalCostPrice));
    }

    /**
     * 计算毛利
     *
     * @param orderPrice 支付金额
     * @param costPrice  成本
     * @return
     */
    private BigDecimal grossMargin(BigDecimal orderPrice, BigDecimal costPrice) {
        BigDecimal grossMargin = BigDecimal.ZERO;
        if (orderPrice.compareTo(BigDecimal.ZERO) > 0) {
            grossMargin = (orderPrice.subtract(costPrice)).multiply(BigDecimal.valueOf(100))
                    .divide(orderPrice, 2, BigDecimal.ROUND_HALF_DOWN);
        }
        return grossMargin;
    }

    private BiSkuSale buildBiSkuSaleFromKids(KidsOrderDetail detail, Date orderDate, OffShop offShop,
                                             List<String> skuCodeList) {
        BiSkuSale skuSale = new BiSkuSale();
        skuSale.setBiDate(orderDate);
        skuSale.setShopNo(offShop.getShopNo());
        skuSale.setShopName(offShop.getShopName());
        skuSale.setProductName(StringUtils.isBlank(detail.getSourceProductName()) ?
                detail.getProductName() : detail.getSourceProductName());
        skuSale.setProductCode(detail.getProductCode());
        skuSale.setSkuCode(detail.getSkuCode());
        skuSale.setShortName(detail.getColor());
        skuSale.setSize(detail.getSizeName());
        skuSale.setAmount(detail.getQuantity());

        if (!skuCodeList.contains(detail.getSkuCode())) {
            skuCodeList.add(detail.getSkuCode());
        }
        return skuSale;
    }
}
